﻿using System;
using System.Collections.Generic;

namespace _01Enum_03NastyFrogs
{
    /// <summary>
    /// 水稻坐标点
    /// </summary>
    internal struct Plant
    {
        public int x;
        public int y;
    }

    class Program
    {
        private static int r;
        private static int c;
        private static int n;

        static void Main(string[] args)
        {
            var rcSplit = Console.ReadLine().Split(' ');
            r = Convert.ToInt32(rcSplit[0]);
            c = Convert.ToInt32(rcSplit[1]);

            n = Convert.ToInt32(Console.ReadLine());

            var plants = new List<Plant>();
            for (var i = 0; i < n; i++)
            {
                var plantSplic = Console.ReadLine().Split(' ');
                var plant = new Plant
                {
                    x = Convert.ToInt32(plantSplic[0]),
                    y = Convert.ToInt32(plantSplic[1])
                };

                plants.Add(plant);
            }

            plants.Sort(ComparePlant);

            var max = 0;

            for (var i = 0; i < n - 2; i++)
            {
                for (var j = 0; j < n - 1; j++)
                {
                    var dX = plants[j].x - plants[i].x;
                    var dY = plants[j].y - plants[i].y;
                    var pX = plants[i].x - dX;
                    var pY = plants[i].y - dY;

                    // 如果第一点的前一点依然落在稻田里面
                    // 说明本次选的第二点导致的 x 方向步长不合理（太小）
                    // 取下一个点为第二点
                    if ((pX >= 1 && pX <= r) && (pY >= 1 && pY <= c))
                    {
                        continue;
                    }

                    // x 方向过早越界了，本次选的第二点不成立
                    // 如果换下一个点作为第二点，x 方向步长只会更大(因为之前排过序)，更不成立
                    // 即本次选的第一点必然是不成立的，那么取下一个点作为第一点再试
                    pX = plants[i].x + (max - 1) * dX;
                    if (pX > r)
                    {
                        break;
                    }

                    // y 方向过早越界了，应换下一点作为第二点再试
                    pY = plants[i].y + (max - 1) * dY;
                    if (pY > c || pY < 1)
                    {
                        continue;
                    }

                    int steps = SearchPath(plants, plants[j], dX, dY);
                    if (steps > max)
                    {
                        max = steps;
                    }
                }
            }

            Console.WriteLine("Max steps = " + max);

            Console.ReadKey();
        }

        private static int SearchPath(List<Plant> plants, Plant secPlant, int dX, int dY)
        {
            int steps = 2;

            var nextPlant = new Plant
            {
                x = secPlant.x + dX,
                y = secPlant.y + dY
            };

            while (nextPlant.x >= 1 && nextPlant.x <= r && nextPlant.y >= 1 && nextPlant.y <= c 
                   && plants.Contains(nextPlant))
            {
                steps++;
                nextPlant.x += dX;
                nextPlant.y += dY;
            }

            if (steps < 3)
            {
                steps = 0;
            }

            return steps;
        }

        // Default comparer for Plant struct.
        private static int ComparePlant(Plant plant1, Plant plant2)
        {
            if (plant1.x == plant2.x)
            {
                if (plant1.y == plant2.y)
                {
                    return 0;
                }

                return plant1.y > plant2.y ? 1 : -1;
            }

            return plant1.x > plant2.x ? 1 : -1;
        }
    }
}
